package com.example.datamanage.service.impl;

import cn.hutool.core.text.csv.CsvUtil;
import cn.hutool.core.text.csv.CsvWriter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.example.datamanage.common.CodeEnum;
import com.example.datamanage.common.FileTypeEnum;
import com.example.datamanage.common.Result;
import com.example.datamanage.exception.MyException;
import com.example.datamanage.mapper.SqlMapper;
import com.example.datamanage.service.SqlService;
import com.example.datamanage.utils.ExportUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.*;
import java.net.URLEncoder;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;

/**
 * @author 28142
 * @description SqlService接口的实现类
 * @date 2023/7/25 14:07
 */
@Service
public class SqlServiceImpl implements SqlService {
    @Autowired
    private SqlMapper sqlMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private DataSource dataSource;
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    ExportUtils exportUtils;
    private static Logger logger = LoggerFactory.getLogger(SqlServiceImpl.class);

    @Override
    public Result executeSql(String sql) {
        // List<List<LinkedHashMap<String, Object>>> list = new ArrayList<>();
        List<Map<String, Object>> list = new ArrayList<>();
        // 拆分sql语句
        String[] sqlArr = sql.split(";");
        // 在for循环外面try catch， 如果出现异常，终止循环，后面的sql不再执行
        try {
            for (String one : sqlArr) {
                // 如果sql是以select开头（去除头部空格、忽略大小写），就继续执行
                if (StrUtil.startWithIgnoreCase(StrUtil.trim(one), "select")) {
                    // 一条sql的返回结果，里面存放字段名和字段值
                    Map<String, Object> map = new HashMap<>();
                    // 一条sql的查询结果
                    List<LinkedHashMap<String, Object>> valList = sqlMapper.executeSql(one);
                    // 将查询结果存到redis中，将其sql作为key
                    redisTemplate.opsForValue().set(StrUtil.trim(one), valList);
                    // 当查询有数据时，获取查询结果的字段名
                    if (valList.size() != 0) {
                        LinkedHashMap valMap = (LinkedHashMap) valList.get(0);
                        // 字段名
                        List<String> nameList = new ArrayList();
                        // 遍历获取字段名
                        for (Object name : valMap.keySet()) {
                            nameList.add((String) name);
                        }
                        // 将查询结果放到map中
                        map.put("sql", one);
                        map.put("valList", valList);
                        map.put("nameList", nameList);
                    }
                    // 将每一条sql执行结果放到list集合中
                    list.add(map);
                } else {
                    return Result.error(CodeEnum.CODE_502.getCode(), "仅支持查询语句", list);
                }
            }
            return Result.success(list);
        } catch (Exception e) {
            // e.printStackTrace();
            return Result.error(CodeEnum.CODE_502.getCode(), e.getCause().getMessage(), list);
        }
    }

    @Override
    public void export(String type, String sql, HttpServletResponse response) {
        logger.info("数据导出准备中···");
        // 根据sql从redis中获取值
        List<LinkedHashMap<String, Object>> list = (List<LinkedHashMap<String, Object>>) redisTemplate.opsForValue().get(StrUtil.trim(sql));
        logger.info("正在获取数据，字段总数" + list.get(0).size() + "个");
        logger.info("正在生成数据包，数据总数" + list.size() + "条");
        exportUtils.export("导出结果", type, list, response);
    }


    @Override
    public Result executeQuery(String mulSql) {
        List<Map> list = new ArrayList<>();
        // List msgList = new ArrayList();
        try (Connection connection = dataSource.getConnection()) {
            // 拆分sql语句
            String[] sqlArr = mulSql.split(";");
            for (String sql : sqlArr) {
                // 如果sql是以select开头（去除头部空格、忽略大小写），就继续执行
                if (StrUtil.startWithIgnoreCase(StrUtil.trim(sql), "select")) {
                    // 这里并没有真正执行查询，只是将用户输入的SQL语句作为参数化的预处理语句
                    try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                        // 执行查询
                        ResultSet resultSet = preparedStatement.executeQuery();
                        // 处理查询结果并返回，map是一条sql的返回结果
                        Map<String, Object> map = new HashMap<>();
                        // resultList是字段值的集合
                        List<Map<String, Object>> resultList = new ArrayList<>();
                        // nameList是字段名的集合
                        List<String> nameList = new ArrayList<>();
                        // 获取结果集中的列数
                        int columnCount = resultSet.getMetaData().getColumnCount();
                        // 获取字段名，存入集合，不论是否有数据，都要查出字段名，因此放在while循环外
                        for (int i = 1; i <= columnCount; i++) {
                            nameList.add(resultSet.getMetaData().getColumnName(i));
                        }
                        // 判断是否有下一行
                        while (resultSet.next()) {
                            // 解析结果集并添加到resultList中
                            // 创建一个用于存放当前行数据的Map
                            Map<String, Object> rowMap = new LinkedHashMap<>();
                            // 遍历每一列，将列名和对应的值存入Map
                            for (int i = 1; i <= columnCount; i++) {
                                String columnName = resultSet.getMetaData().getColumnName(i);
                                Object columnValue = resultSet.getObject(i);
                                rowMap.put(columnName, columnValue);
                            }
                            // 将当前行的Map添加到结果列表中
                            resultList.add(rowMap);
                        }
                        // 将查询结果存到redis中，将其sql作为key
                        redisTemplate.opsForValue().set(StrUtil.trim(sql), resultList);
                        map.put("sql", StrUtil.trim(sql));
                        map.put("nameList", nameList);
                        map.put("resultList", resultList);
                        list.add(map);
                    }
                } else {
                    return Result.error(CodeEnum.CODE_401.getCode(), "仅支持sql查询", list);
                }
            }
            return Result.success(list);
        } catch (SQLException e) {
            // 处理异常
            e.printStackTrace();
            return Result.error(CodeEnum.CODE_502.getCode(), e.getMessage(), list);
        }
        // return null;
    }

    @Override
    public Result showTables() {
        String sql = "show full tables where table_type = 'BASE TABLE'";
        return Result.success(jdbcTemplate.queryForList(sql));
    }

    @Override
    public Result showViews() {
        String sql = "show full tables where table_type = 'VIEW'";
        return Result.success(jdbcTemplate.queryForList(sql));
    }



}
